#include <Editor/StdAfx.h>
#include "ResourcePage.h"
#include "ResourceTree.h"
#include "wxIDs.h"
#include "GameToolApp.h"
#include "ReadDirectoryChanges.h"
#include "../GameLib/EngineFacade.h"
#include "../DebugUtils/DebugUtils.h"

#include <wx/filename.h>

BEGIN_EVENT_TABLE(ResourcePage, wxPanel)
	EVT_BUTTON(ID_BUTTON_RELOAD_ALL_RESOURCES, OnReloadAllButton)
END_EVENT_TABLE()

class FileWatcherThread : public wxThread
{
public:
	FileWatcherThread(ResourcePage* owner);
	void End();

protected:
	virtual void* Entry();

private:
	CReadDirectoryChanges mFileSystemWatcher;
	ResourcePage* mResourcePage;
	bool mTerminated;
};

ResourcePage::ResourcePage(wxWindow* parent)
	: wxPanel(parent)
{
	//mFileSystemWatcher.Connect(wxEVT_FSWATCHER, wxFileSystemWatcherEventHandler(ResourcePage::OnFileChanged), 0, this);
	m_pWatcherThread = new FileWatcherThread(this);
	m_pWatcherThread->Create();
	m_pWatcherThread->Run();
	m_pWatcherThread->SetPriority(WXTHREAD_MIN_PRIORITY);
	
	wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL);
	SetSizer(topSizer);
	topSizer->Add(new wxButton(this, ID_BUTTON_RELOAD_ALL_RESOURCES, _("Reload All")), wxSizerFlags().Border());
	mTree = new ResourceTree(this);
	topSizer->Add( mTree, 1, wxEXPAND );
}


ResourcePage::~ResourcePage(void)
{
	FileWatcherThread* pThread = dynamic_cast<FileWatcherThread*>(m_pWatcherThread);
	assert(pThread);
	pThread->End();
	m_pWatcherThread->Kill();
}

void ResourcePage::RefreshParticleSystemTree()
{
	mTree->RefreshParticleSystemTree();
}

void ResourcePage::RefreshMeshTree()
{
	mTree->RefreshMeshTree();
}

void ResourcePage::OnReloadAllButton(wxCommandEvent& e)
{
	bool success = EngineFacade::ReloadAllResources();
	if (success)
	{
		wxGetApp().Message(_("Resources reloaded."));
	}
}

/*
void ResourcePage::OnFileChanged(wxFileSystemWatcherEvent& e)
{
	static wxString lastPath;
	static wxDateTime lastTime = wxDateTime::Now();
	if (e.GetChangeType() == wxFSW_EVENT_MODIFY)
	{
		wxFileName filename(e.GetPath());
		wxString fullPath = filename.GetFullPath();
		if (fullPath == lastPath && wxDateTime::Now() - lastTime < wxTimeSpan(0, 0, 0, 1))
		{
			return;
		}
		wxString msg = wxString::Format( _("File %s has been modified."),  filename.GetFullName() );
		wxGetApp().Message(msg);
		if (filename.GetExt().Lower() == _T("material"))
		{
			DebugUtils::Warning(DEFAULT_DEBUG_ARG, "Following material is reloading...");
			wxString msg = wxString::Format(_T("	%s"), filename.GetFullPath());
			DebugUtils::Warning(msg.mb_str());
			bool success = EngineFacade::ReloadMaterial(filename.GetFullName().mb_str());
			wxGetApp().Message(_("The modified resource is reloaded."));
		}

		lastPath = fullPath;
		lastTime = wxDateTime::Now();
	}
}
*/

void ResourcePage::CheckFileModification()
{
	static wxString lastPath;
	static wxDateTime lastTime = wxDateTime::Now();

	wxCriticalSectionLocker lock(mCS);
	if (!mModifiedFiles.empty())
	{
		wxFileName filename( wxString(mModifiedFiles.front().c_str()) );
		mModifiedFiles.pop();
		wxString fullPath = filename.GetFullPath();
		if (fullPath == lastPath && wxDateTime::Now() - lastTime < wxTimeSpan(0, 0, 0, 1))
		{
			return;
		}
		if (filename.GetExt().Lower() == _T("material"))
		{
			DebugUtils::Warning(DEFAULT_DEBUG_ARG, "Following material is reloading...");
			wxString msg = wxString::Format(_T("	%s"), filename.GetFullPath());
			DebugUtils::Warning(msg.mb_str());
			bool success = EngineFacade::ReloadMaterial(filename.GetFullName().mb_str());
			wxGetApp().Message(_("The modified resource is reloaded."));
		}

		lastPath = fullPath;
		lastTime = wxDateTime::Now();	
	}
}

void ResourcePage::AddModifiedFile(const std::wstring& filename)
{
	wxCriticalSectionLocker lock(mCS);
	mModifiedFiles.push(filename);
}

FileWatcherThread::FileWatcherThread(ResourcePage* owner)
	: wxThread()
	, mResourcePage(owner)
	, mTerminated(false)
{
	const DWORD dwNotificationFlags = FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION;
	mFileSystemWatcher.AddDirectory( _T(".\\Data\\"), true, dwNotificationFlags );
}

void FileWatcherThread::End()
{
	mFileSystemWatcher.Terminate();
	mTerminated = true;
}

void* FileWatcherThread::Entry()
{
	const HANDLE handles[] = { mFileSystemWatcher.GetWaitHandle() };

	while (!mTerminated)
	{
		DWORD rc = ::WaitForMultipleObjectsEx(_countof(handles), handles, false, INFINITE, true);
		switch (rc)
		{
		case WAIT_OBJECT_0 + 0:
			// We've received a notification in the queue.
			{
				DWORD dwAction;
				std::wstring filename;
				if (mFileSystemWatcher.CheckOverflow())
				{
					DebugUtils::Warning(DEFAULT_DEBUG_ARG, "FileSystemWatcher overflowed.");
				}
				else
				{
					mFileSystemWatcher.Pop(dwAction, filename);
					mResourcePage->AddModifiedFile(filename);					
				}
			}
			break;
		case WAIT_IO_COMPLETION:
			// Nothing to do.
			break;
		}
	}

	return 0;
}